package com.jzo2o.health.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.trade.NativePayApi;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.request.NativePayReqDTO;
import com.jzo2o.api.trade.dto.response.NativePayResDTO;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.PayChannelEnum;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.constants.MqConstants;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.DateUtils;
import com.jzo2o.common.utils.IdUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.handler.OrdersHandler;
import com.jzo2o.health.mapper.OrdersCancelledMapper;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.*;
import com.jzo2o.health.model.dto.request.OrdersCancelReqDTO;
import com.jzo2o.health.model.dto.request.OrdersPageQueryReqDTO;
import com.jzo2o.health.model.dto.request.PlaceOrderReqDTO;
import com.jzo2o.health.model.dto.response.*;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.*;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.rabbitmq.client.RabbitClient;
import org.apache.poi.sl.usermodel.ObjectMetaData;
import org.aspectj.runtime.internal.cflowstack.ThreadStackImpl11;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.convert.DtoInstantiatingConverter;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * TODO
 *
 * @Author lyh
 * @Date 2024/12/14 9:44
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersService {
    @Autowired
    private ISetmealService setmealService;
    @Autowired
    private IMemberService memberService;

    @Autowired
    private NativePayApi nativePayApi;

    @Autowired
    private IOrdersService owner;

    @Autowired
    private IReservationSettingService reservationSettingService;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 下单接口
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlaceOrderResDTO place(PlaceOrderReqDTO dto) {
       if(ObjectUtils.isNull(dto)){
           throw new BadRequestException("参数异常");
       }
        SetmealDetailResDTO detail = setmealService.findDetail(dto.getSetmealId());
       if(ObjectUtils.isNull(detail)){
           throw new BadRequestException("套餐已无效");
       }
       if((!dto.getCheckupPersonSex().toString().equals(detail.getSex()))&&(!detail.getSex().equals(String.valueOf(0)))){
           throw new BadRequestException("体检性别不对");
       }
        Orders orders = BeanUtils.copyBean(dto, Orders.class);
        CurrentUserInfo currentUserInfo = UserThreadLocal.currentUser();
        orders.setMemberId(currentUserInfo.getId());
        Member member = memberService.getById(currentUserInfo.getId());
        orders.setMemberPhone(member.getPhone());//设置预约人手机号
        orders.setSetmealAge(detail.getAge());
        orders.setSetmealImg(detail.getImg());
        orders.setSetmealName(detail.getName());
        orders.setSetmealPrice(BigDecimal.valueOf(detail.getPrice()));
        orders.setSetmealSex(Integer.valueOf(detail.getSex()));
        orders.setSetmealRemark(detail.getRemark());
        orders.setSortBy(DateUtils.toEpochMilli(LocalDateTime.now()));//设置排序字段  当前时间的时间戳
        orders.setOrderStatus(0);//设置订单状态
        orders.setPayStatus(0);
        boolean save = this.save(orders);
        if(!save){
            throw new DBException("添加订单失败");
        }
        boolean update = reservationSettingService.lambdaUpdate()
                .setSql("reservations=reservations+1")
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                .update();
        if(!update){
            throw new DBException("更新预约表失败");
        }
        Message msg = MessageBuilder.withBody(orders.getId().toString().getBytes())
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)
                //.setExpiration("5000")
                .setHeader("x-delay","60000")
                .build();
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(MqConstants.Exchanges.ORDERS,
                MqConstants.RoutingKeys.ORDERS_CANCEL_KEY,
                msg,
                correlationData
        );
        return new PlaceOrderResDTO(orders.getId());
    }
    @Autowired
    private TradeProperties tradeProperties;

    /**
     * 下单支付
     * @param id
     * @param tradingChannel
     * @return
     */
    @Override
    public OrdersPayResDTO pay(Long id, PayChannelEnum tradingChannel) {
        Orders orders = this.getById(id);
        //判断订单是否存在
        if(ObjectUtils.isNull(orders)){
            throw new BadRequestException("订单不存在");
        }
        //判断订单是否支付过
        if(orders.getPayStatus().equals(1)){
            OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
            ordersPayResDTO.setProductOrderNo(orders.getId());
            return ordersPayResDTO;
        }
        //是否更改过支付渠道
        boolean changeChannel = false;
        if(orders.getTradingChannel()!=null&&!orders.getTradingChannel().equals(tradingChannel)){
            changeChannel=true;
        }

        Long enterpriseId = ObjectUtils.equals(tradingChannel, PayChannelEnum.WECHAT_PAY) ? tradeProperties.getWechatEnterpriseId() : tradeProperties.getAliEnterpriseId();
        NativePayReqDTO payReqDTO = new NativePayReqDTO();
        //productOrderNo：是业务系统的订单号
        payReqDTO.setProductOrderNo(id);
        //tradingAmount：支付金额
        payReqDTO.setTradingAmount(new BigDecimal(0.01));
        //enterpriseId：商户号，进入微信或支付宝商户平台获取。
        payReqDTO.setEnterpriseId(enterpriseId);
        //memo: 备注信息
        payReqDTO.setMemo(orders.getSetmealName());
        //tradingChannel：微信支付传入WECHAT_PAY，支付宝支付传入ALI_PAY
        payReqDTO.setTradingChannel(tradingChannel);
        //changeChannel：当用户先微信支付，然后又进行支付宝支付表示切换了支付渠道，此时传入true
        payReqDTO.setChangeChannel(changeChannel);
        //productAppId: 业务系统标识，服务调用方的标识字符串
        payReqDTO.setProductAppId(tradeProperties.getProductAppId());
        //支付
        NativePayResDTO dto = nativePayApi.createDownLineTrading(payReqDTO);
        if(dto==null){
            throw new BadRequestException("支付请求失败");
        }
        owner.updatePay(id,dto);
        OrdersPayResDTO ordersPayResDTO=BeanUtils.copyBean(dto,OrdersPayResDTO.class);
        ordersPayResDTO.setPayStatus(2);
        return ordersPayResDTO;
    }

    /**
     * 支付成功后更新订单状态
     * @param id
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePay(Long id, NativePayResDTO dto) {
        boolean update = this.lambdaUpdate()
                .set(Orders::getTradingChannel, dto.getTradingChannel())
                .set(Orders::getTradingOrderNo, dto.getTradingOrderNo())
                .eq(Orders::getId, id)
                .update();
        if(!update){
            throw new DBException("修改订单失败");
        }
    }
    @Autowired
    private TradingApi tradingApi;
    /**
     * 查询支付结果
     * @param id
     * @return
     */
    @Override
    public OrdersPayResDTO payResult(Long id) {
        Orders orders = this.getById(id);
        if(orders==null){
            throw new BadRequestException("订单不存在");
        }
        if(orders.getTradingOrderNo()==null){
            throw new BadRequestException("错误订单请求");
        }
        OrdersPayResDTO ordersPayResDTO = BeanUtils.copyBean(orders, OrdersPayResDTO.class);
        ordersPayResDTO.setProductOrderNo(id);
        //判断订单是否支付过
        if(orders.getPayStatus().equals(1)){
            return ordersPayResDTO;
        }
        TradingResDTO result = tradingApi.findTradResultByTradingOrderNo(orders.getTradingOrderNo());
        //支付结果查询成功
        if(result!=null&& result.getTradingState() == TradingStateEnum.YJS){
            owner.paySuccess(id, result.getTransactionId(),result.getPaySuccessTime());
            ordersPayResDTO.setPayStatus(1);
            ordersPayResDTO.setQrCode("");
        }

        return ordersPayResDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(Long id, String transactionId, LocalDateTime paySuccessTime) {
        boolean update = this.lambdaUpdate()
                .set(Orders::getPayStatus, 1)
                .set(Orders::getTransactionId, transactionId)
                .set(Orders::getPayTime, paySuccessTime)
                .set(Orders::getOrderStatus, 100)
                .eq(Orders::getId, id)
                .update();
        if(!update){
            throw new DBException("修改订单失败");
        }
    }
    /**
     * 取消未支付的订单
     * @param dto
     */

    @Autowired
    private OrdersCancelledMapper ordersCancelledMapper;

    @Autowired
    private ApplicationContext applicationContext;
    @Override
    public void cancel(OrdersCancelReqDTO dto) {
        Orders orders = this.getById(dto.getId());
        if(orders==null){
            throw new BadRequestException("订单不存在");
        }
        if((!orders.getOrderStatus().equals(0))&&(!orders.getOrderStatus().equals(100))){
            throw new BadRequestException("订单状态非法");
        }
        if(orders.getOrderStatus().equals(0)){
            //未支付的订单
            owner.cancelOrdersByNoPay(orders,dto.getCancelReason(),false);
        }else{
            //支付后的订单
            OrdersHandler ordersHandler = applicationContext.getBean(OrdersHandler.class);
            ordersHandler.cancelOrderByDispatching(orders,dto.getCancelReason(),UserThreadLocal.currentUser());

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrdersByNoPay(Orders orders, String cancelReason, boolean b) {
        OrdersCancelled cancelled = new OrdersCancelled();
        cancelled.setId(orders.getId());
        //非系统自动取消
        if(!b){
            cancelled.setCancellerId(UserThreadLocal.currentUserId());//取消人id
            cancelled.setCancellerName(UserThreadLocal.currentUser().getName());//取消人name
            cancelled.setCancellerType(UserThreadLocal.currentUser().getUserType());//取消人type
        }

        cancelled.setCancelTime(LocalDateTime.now());
        cancelled.setCancelReason(cancelReason);//取消原因
        int insert = ordersCancelledMapper.insert(cancelled);
        if(insert==0){
            throw new DBException("取消记录添加失败");
        }
        boolean update = this.lambdaUpdate()
                .set(Orders::getOrderStatus, 400)
                .eq(Orders::getId, orders.getId())
                .update();
        if(!update){
            throw new DBException("修改订单失败");
        }
        boolean update1 = reservationSettingService.lambdaUpdate()
                .setSql("reservations=reservations-1")
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                .update();
        if(!update1){
            throw new DBException("更新预约表失败");
        }
    }

    @Override
    public List<OrdersResDTO> pageQuery(Integer ordersStatus, Long sortBy) {
        List<Orders> list = this.lambdaQuery()
                .eq(Orders::getMemberId,UserThreadLocal.currentUserId())
                .eq(ordersStatus != null, Orders::getOrderStatus, ordersStatus)
                .orderByDesc(Orders::getSortBy)
                .lt(sortBy!=null,Orders::getSortBy,sortBy)
                .last("limit 10")
                .list();
        List<OrdersResDTO> ordersResDTOS = BeanUtils.copyToList(list, OrdersResDTO.class);
        return ordersResDTOS;
    }

    @Override
    public OrdersDetailResDTO detail(Long id) {
        Orders orders = this.getById(id);
        OrdersDetailResDTO ordersDetailResDTO = BeanUtils.copyBean(orders, OrdersDetailResDTO.class);
        return ordersDetailResDTO;
    }

    @Override
    public PageResult<OrdersResDTO> adminPageQuery(OrdersPageQueryReqDTO dto) {
        IPage page = new Page(dto.getPageNo(),dto.getPageSize());
        IPage page1 = this.lambdaQuery()
                .eq(dto.getOrderStatus() != null, Orders::getOrderStatus, dto.getOrderStatus())
                .like(dto.getMemberPhone() != null, Orders::getMemberPhone, dto.getMemberPhone())
                .orderBy(dto.getOrderBy1() != null, dto.getIsAsc1(), Orders::getSortBy)
                .page(page);
        List<OrdersResDTO> records = page1.getRecords();
        PageResult<OrdersResDTO> dtoPageResult = new PageResult<>();
        dtoPageResult.setTotal(page1.getTotal());
        dtoPageResult.setPages(page1.getPages());
        dtoPageResult.setList(records);
        return dtoPageResult;
    }

    @Override
    public OrdersCountResDTO countByStatus() {
        OrdersCountResDTO dto = this.getBaseMapper().adminCountByStatus();
        Integer count = this.lambdaQuery()
                .count();
        dto.setTotalCount(count);
        return dto;
    }

    @Override
    public AdminOrdersDetailResDTO aggregation(Long id) {
        Orders orders = this.getById(id);
        if(orders==null){
            throw new BadRequestException("订单不存在");
        }
        AdminOrdersDetailResDTO.OrderInfo orderInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.OrderInfo.class);
        AdminOrdersDetailResDTO dto = new AdminOrdersDetailResDTO();
        dto.setOrderInfo(orderInfo);
        AdminOrdersDetailResDTO.PayInfo payInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.PayInfo.class);
        if(payInfo!=null){
            if(payInfo.getPayStatus()>0){
                payInfo.setPayStatus(1);
            }
            payInfo.setThirdOrderId(orders.getTransactionId());
            dto.setPayInfo(payInfo);
        }
        OrdersCancelled cancelled = ordersCancelledMapper.selectById(orders.getId());
        if(orders.getOrderStatus()==400||orders.getOrderStatus()==300) {
            AdminOrdersDetailResDTO.CancelInfo cancelInfo = BeanUtils.copyBean(cancelled, AdminOrdersDetailResDTO.CancelInfo.class);
            dto.setCancelInfo(cancelInfo);
        }
        if(orders.getOrderStatus()==300){
            AdminOrdersDetailResDTO.RefundInfo refundInfo = BeanUtils.copyBean(orders, AdminOrdersDetailResDTO.RefundInfo.class);
            refundInfo.setRefundStatus(orders.getPayStatus());
            refundInfo.setCancelReason(cancelled.getCancelReason());
            refundInfo.setCancelTime(cancelled.getCancelTime());
            dto.setRefundInfo(refundInfo);
        }
        return dto;
    }
}
